import time
from datetime import datetime
from typing import Tuple

from flask_restx import abort


class BaseManager:
    """
    管理器基类
    未提供Error类型时, 默认 Exception
    """

    Model = None
    Error = Exception

    error_func = None

    def __init__(self, need_model=False, is_abort=True):

        if need_model:
            assert self.Model, "need_model为True但未指定Model!"

        if is_abort:
            self.error_func = self.__error_abort
        else:
            self.error_func = self.__other_error

    def get_obj_or_error(self, *args, **kwargs):
        obj = self.Model.query.filter(*args).filter_by(**kwargs).first()
        if not obj:
            self.error_func("对象不存在!")
        return obj

    def get_obj_or_create(self, db, model=None, defaults=None, **kwargs) -> Tuple:
        """
        获取对象/创建对象
        """
        model = model or self.Model
        defaults = defaults or {}
        obj = model.query.filter_by(**kwargs).one_or_none()
        operator = self.get_operator()
        if obj:
            return obj, False
        if operator:
            kwargs.update(
                {"creator_name": operator.account_name, "creator_id": operator.id}
            )
        kwargs.update(defaults)
        obj = model()
        # 设置属性
        for k, v in kwargs.items():
            setattr(obj, k, v)

        db.session.add(obj)
        return obj, True

    def update_or_create(self, db, model=None, defaults=None, **kwargs) -> Tuple:
        """
        更新/创建
        """
        model = model or self.Model
        defaults = defaults or {}
        obj = model.query.filter_by(**kwargs).one_or_none()
        operator = self.get_operator()
        if obj:
            if operator:
                defaults.update({"editor_name": operator.account_name})
            for k, v in defaults.items():
                setattr(obj, k, v)
            return obj, False
        if operator:
            kwargs.update(
                {"creator_name": operator.account_name, "creator_id": operator.id}
            )
        kwargs.update(defaults)
        obj = model()
        # 设置属性
        for k, v in kwargs.items():
            setattr(obj, k, v)
        db.session.add(obj)
        return obj, True

    @staticmethod
    def get_operator():
        """
        有登录认证的接口才可调用此方法
        """
        from app.common.libs import auth

        return auth.current_user()

    @staticmethod
    def __error_abort(msg, code=400, **kwargs):
        abort(code, message=msg)

    def __other_error(self, msg, **kwargs):
        raise self.Error(msg)

    def str_to_datetime(self, time_str, format_str="%Y-%m-%d %H:%M:%S") -> datetime:
        """
        字符串 -> datetime
        is_utc 是否转为utc时间
        """
        try:
            r = datetime.strptime(time_str, format_str)
        except (ValueError, TypeError):
            self.error_func(f"时间格式错误! 应为: {format_str}")
        else:
            return r

    @staticmethod
    def local_datetime_to_utc(local_datetime: datetime) -> datetime:
        """
        本地时间转utc
        """
        return datetime.utcfromtimestamp(time.mktime(local_datetime.timetuple()))
